package fhq.hcmute.modernshopping.camera;

import java.io.IOException;

import android.content.Context;
import android.hardware.Camera;
import android.hardware.Camera.Parameters;
import android.hardware.Camera.Size;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.SurfaceHolder;
import fhq.hcmute.modernshopping.ProjectUtil;
import fhq.hcmute.modernshopping.R;
import fhq.hcmute.modernshopping.activities.ScanQrCodeActivity;
import fhq.hcmute.modernshopping.activities.ScanQrCodeActivity.ScanQrCodeHandler;
import fhq.hcmute.qrcode.QRCode;
import fhq.hcmute.qrcode.QRCodeReader;
import fhq.hcmute.qrcode.common.BinaryImage;
import fhq.hcmute.qrcode.util.QRCodeException;

/**
 * @author: Hien Nguyen Le
 * @emai: hien.nguyenle.it@gmail.com
 * 
 */
public class CameraControls {
	public static final String TAG = "nglehien";
	private Camera camera;
	private Handler autofocusHandler;
	private static CameraControls instance = null;
	private static final long TIME_DELAY = 2000L;
	private boolean isScanningQrCode = false;
	private Context context;

	private CameraControls() {
		try {
			openCamera();
			autofocusHandler = new Handler();
			isScanningQrCode = true;
			camera.stopPreview();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public static CameraControls getCameraControls() {
		if (instance == null) {
			instance = new CameraControls();
		}
		return instance;
	}

	public CameraPreview showCameraPreview(Context context,
			SurfaceHolder surfaceHolder) {
		this.context = context;
		return new CameraPreview(context, camera, previewCallback,
				autoFocusCallback, surfaceHolder);
	}

	public boolean openCamera() {
		try {
			this.camera = Camera.open();
			return true;
		} catch (RuntimeException e) {
			Log.d(TAG, "openCamera error:" + e.getMessage());
		}
		return false;
	}

	public boolean toggleFlashLight() {
		Parameters parameters = camera.getParameters();
		String flashMode = parameters.getFlashMode();
		boolean isFlashOn = false;
		try {
			Thread.sleep(500);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		if (flashMode.equals(Parameters.FLASH_MODE_OFF)) {
			parameters.setFlashMode(Parameters.FLASH_MODE_TORCH);
			isFlashOn = true;
		} else {
			parameters.setFlashMode(Parameters.FLASH_MODE_OFF);
			isFlashOn = false;
		}
		this.camera.setParameters(parameters);

		return isFlashOn;
	}

	public void stopScanQrCode() {
		this.isScanningQrCode = false;
		this.camera.cancelAutoFocus();
	}

	public void startScanQrCode() {
		this.isScanningQrCode = true;
		this.camera.autoFocus(autoFocusCallback);
	}

	public void stopReview() {
		if (camera != null) {
			camera.stopPreview();
		}
	}

	public void startPreview() {
		if (camera != null) {
			camera.startPreview();
		}
	}

	public boolean stopCamera() {
		if (camera != null) {
			camera.setPreviewCallback(null);
			camera.release();
			isScanningQrCode = false;
			instance = null;
			return true;
		}
		return false;
	}

	private Runnable autoFocus = new Runnable() {

		@Override
		public void run() {
			if (isScanningQrCode) {
				camera.autoFocus(autoFocusCallback);
			}
		}
	};

	private Camera.AutoFocusCallback autoFocusCallback = new Camera.AutoFocusCallback() {
		@Override
		public void onAutoFocus(boolean success, Camera camera) {
			autofocusHandler.postDelayed(autoFocus, TIME_DELAY);
		}
	};

	public byte[] YUVtoGrayScale(byte[] paramArrayOfByte, int width, int height) {
		int i = width * height;
		byte[] arrayOfByte = new byte[i];
		for (int j = 0; j < i; j++) {

			int k = -16 + (0xFF & paramArrayOfByte[j]);
			if (k < 0)
				k = 0;
			if (k > 255)
				k = 255;
			arrayOfByte[j] = ((byte) (k | (0xFF000000 | k << 16 | k << 8)));
		}
		return arrayOfByte;
	}

	private Camera.PreviewCallback previewCallback = new Camera.PreviewCallback() {
		@Override
		public void onPreviewFrame(byte[] data, Camera camera) {
			if (isScanningQrCode) {
				Size size = camera.getParameters().getPreviewSize();
				byte[] ddt = YUVtoGrayScale(data, size.width, size.height);
				BinaryImage binaryImage = new BinaryImage(size.width,
						size.height, ddt);
				try {
					QRCodeReader reader = new QRCodeReader(binaryImage);
					QRCode qrCode = reader.decode();
					if (qrCode != null) {
						ProjectUtil.playSound(context, R.raw.beep);
						Handler handler = ScanQrCodeHandler.getQrCodeHandler();
						Message message = handler.obtainMessage(
								ScanQrCodeActivity.SCAN_SUCCESSFUL, qrCode);
						handler.sendMessage(message);
						stopScanQrCode();
					}
				} catch (IOException e) {
					e.printStackTrace();
				} catch (QRCodeException e) {
					e.printStackTrace();
				}
			}
		}
	};
}
